/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Creator.h"
#include <Gluck.h>
#include <Converter.h>
#include <logs/Log.h>
#include <WindowImpl.h>

#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"dxguid.lib")

namespace liba
{
namespace input
{
namespace hard
{
namespace directx8
{

static std::vector<IDirectInputDevice8 *> enum_joysticks;
static std::vector<IDirectInputDevice8 *> enum_mouses;
static HWND Wnd;

static BOOL FAR PASCAL InitJoystickInput( LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef ) 
{ 
	IDirectInput8 * di =(IDirectInput8 *) pvRef;
	IDirectInputDevice8 * pdev = 0;
	
	if( di->CreateDevice( pdinst->guidInstance,	&pdev, NULL ) != DI_OK )
	{
		return DIENUM_CONTINUE;
	}

	if( pdev->SetCooperativeLevel( Wnd,
		DISCL_EXCLUSIVE | DISCL_BACKGROUND ) != DI_OK )
//		DISCL_NONEXCLUSIVE | DISCL_FOREGROUND ) != DI_OK )
	{
		pdev->Release();
		pdev = NULL;
		return DIENUM_CONTINUE;
	}

	enum_joysticks.push_back( pdev );
	return DIENUM_CONTINUE;
}


static BOOL FAR PASCAL InitMouseInput( LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef ) 
{ 
	IDirectInput8 * di =(IDirectInput8 *) pvRef;
	IDirectInputDevice8 * pdev = 0;
	
	if( di->CreateDevice( pdinst->guidInstance,	&pdev, NULL ) != DI_OK )
	{
		return DIENUM_CONTINUE;
	}

	if( pdev->SetCooperativeLevel( Wnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND ) != DI_OK )
	{
		pdev->Release();
		pdev = NULL;
		return DIENUM_CONTINUE;
	}

	enum_mouses.push_back( pdev );
	return DIENUM_CONTINUE;
}

Creator::Creator(bool init_mouse, bool init_joystick)
:	DI( 0 )
{
	Wnd = get_window()->get_wnd();
	enum_joysticks.clear();
	HRESULT hr;
    if( (hr = DirectInput8Create( get_window()->get_instance(), DIRECTINPUT_VERSION, IID_IDirectInput8A, (void**)&DI, NULL)) !=DI_OK)
	{
		logs::log() << logs::error << "DirectInput not found\n";
		return;
	}

	if(init_joystick)
	{
		if( ( hr = DI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
			InitJoystickInput, DI, DIEDFL_ATTACHEDONLY ) ) != DI_OK )
		{
			logs::log() << logs::error << "DirectInput joystick enumeration failed\n";
		}
	}

	for( int j = 0; j != enum_joysticks.size(); ++j )
	{
		DIDEVICEINSTANCE dev_instance = {sizeof(DIDEVICEINSTANCE)};
		enum_joysticks[j]->GetDeviceInfo(&dev_instance);
		std::string joy_name = dev_instance.tszInstanceName;

		Joystick * joystick = new Joystick( enum_joysticks[j], joy_name );
		if( joystick->is_valid() )
			joysticks.push_back( joystick );
		else
		{
			delete joystick; joystick = 0;
		}
	}

	if(init_mouse)
	{
		if( ( hr = DI->EnumDevices( DI8DEVCLASS_POINTER,  
			InitMouseInput, DI, DIEDFL_ALLDEVICES  ) ) != DI_OK )
		{
			logs::log() << logs::error << "DirectInput mouse enumeration failed\n";
		}
	}

	for( int j = 0; j != enum_mouses.size(); ++j )
	{
		DIDEVICEINSTANCE dev_instance = {sizeof(DIDEVICEINSTANCE)};
		enum_mouses[j]->GetDeviceInfo(&dev_instance);
		std::string mouse_name = dev_instance.tszInstanceName;


		Mouse * mouse = new Mouse( enum_mouses[j], mouse_name );
		if( mouse->is_valid() )
			mouses.push_back( mouse );
		else
		{
			delete mouse; mouse = 0;
		}
	}

	start();
	set_priority( 1 );
}

void Creator::run()
{
	while( !need_termination() )
	{
		for( int j = 0; j != joysticks.size(); ++j )
		{
			joysticks[j]->poll( 10 );
		}
		for( int j = 0; j != mouses.size(); ++j )
		{
			mouses[j]->poll( 10 );
		}
		Sleep( 10 );
	}
}

Creator::~Creator()
{
	request_termination();
	wait_termination();
	while( joysticks.size() )
	{
		delete joysticks.back(); joysticks.pop_back();
	}
	while( mouses.size() )
	{
		delete mouses.back(); mouses.pop_back();
	}
	if( DI )
	{
		DI->Release(); DI = 0;
	}
}

} // namespace directx8
} // namespace hard
} // namespace input
} // namespace liba


